// 📁 service/impl/BorrowServiceImpl.java
package com.library.management.service.impl;

import com.library.management.entity.Book;
import com.library.management.entity.BorrowRecord;
import com.library.management.entity.User;
import com.library.management.enums.BorrowStatus;
import com.library.management.repository.BookRepository;
import com.library.management.repository.BorrowRecordRepository;
import com.library.management.repository.UserRepository;
import com.library.management.service.BorrowService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
 * 借阅服务实现类
 * 处理借阅相关的业务逻辑实现
 */
@Service
@Transactional
@RequiredArgsConstructor
@Slf4j
public class BorrowServiceImpl implements BorrowService {

    private final BorrowRecordRepository borrowRecordRepository;
    private final UserRepository userRepository;
    private final BookRepository bookRepository;

    // 系统配置参数（可以从配置表或配置文件中读取）
    private static final int MAX_RENEW_TIMES = 1; // 最大续借次数
    private static final int BORROW_DAYS = 30; // 借阅天数
    private static final int RENEW_DAYS = 30; // 续借天数

    @Override
    public BorrowRecord save(BorrowRecord borrowRecord) {
        log.info("保存借阅记录: {}", borrowRecord.getId());
        return borrowRecordRepository.save(borrowRecord);
    }

    @Override
    public BorrowRecord update(Long id, BorrowRecord borrowRecord) {
        log.info("更新借阅记录: {}", id);

        BorrowRecord existingRecord = borrowRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + id));

        // 更新允许修改的字段
        existingRecord.setDueDate(borrowRecord.getDueDate());
        existingRecord.setActualReturnDate(borrowRecord.getActualReturnDate());
        existingRecord.setStatus(borrowRecord.getStatus());
        existingRecord.setRenewTimes(borrowRecord.getRenewTimes());
        existingRecord.setOverdueDays(borrowRecord.getOverdueDays());
        existingRecord.setOverdueFine(borrowRecord.getOverdueFine());
        existingRecord.setFinePaid(borrowRecord.getFinePaid());

        return borrowRecordRepository.save(existingRecord);
    }

    @Override
    public void delete(Long id) {
        log.info("删除借阅记录: {}", id);
        borrowRecordRepository.deleteById(id);
    }


    @Override
    public Optional<BorrowRecord> findById(Long id) {
        return borrowRecordRepository.findById(id);
    }
    @Override
    public List<BorrowRecord> findAll() {
        return borrowRecordRepository.findAll();
    }

    @Override
    public Page<BorrowRecord> findAll(Pageable pageable) {
        return borrowRecordRepository.findAll(pageable);
    }

    @Override
    public boolean exists(Long id) {
        return borrowRecordRepository.existsById(id);
    }

    @Override
    public BorrowRecord borrowBook(Long userId, Long bookId, LocalDateTime borrowDate, LocalDateTime dueDate) {
        log.info("用户 {} 借阅图书 {}", userId, bookId);

        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在: " + userId));
        Book book = bookRepository.findById(bookId)
                .orElseThrow(() -> new RuntimeException("图书不存在: " + bookId));

        // 检查用户是否可以借书
        if (!user.canBorrowBook()) {
            throw new RuntimeException("用户无法借书，可能因为状态非活跃或借书数量已达上限");
        }

        // 检查图书是否可以借阅
        if (!book.isAvailableForBorrow()) {
            throw new RuntimeException("图书不可借阅，可能已被借完或状态不可用");
        }

        // 检查用户是否已经借了这本书且未归还
        if (isBookBorrowedByUser(userId, bookId)) {
            throw new RuntimeException("用户已经借阅了该图书且未归还");
        }

        // 创建借阅记录
        BorrowRecord borrowRecord = new BorrowRecord();
        borrowRecord.setUser(user);
        borrowRecord.setBook(book);
        borrowRecord.setBorrowDate(borrowDate != null ? borrowDate : LocalDateTime.now());
        borrowRecord.setDueDate(dueDate != null ? dueDate : LocalDateTime.now().plusDays(BORROW_DAYS));
        borrowRecord.setStatus(BorrowStatus.BORROWED);

        // 保存借阅记录
        BorrowRecord savedRecord = borrowRecordRepository.save(borrowRecord);

        // 更新图书可借册数
        book.borrowBook();
        bookRepository.save(book);

        return savedRecord;
    }

    @Override
    public BorrowRecord returnBook(Long borrowRecordId, LocalDateTime returnDate) {
        log.info("归还借阅记录: {}", borrowRecordId);

        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        if (borrowRecord.getStatus() == BorrowStatus.RETURNED) {
            throw new RuntimeException("该借阅记录已经归还");
        }

        // 设置归还日期
        LocalDateTime actualReturnDate = returnDate != null ? returnDate : LocalDateTime.now();
        borrowRecord.setActualReturnDate(actualReturnDate);

        // 计算逾期天数和罚款
        borrowRecord.setOverdueDays(borrowRecord.calculateOverdueDays());
        // 这里可以调用罚款服务生成罚款记录，假设逾期罚款率为0.1元/天
        // fineService.createOverdueFine(borrowRecord, 0.1);

        // 更新状态为已归还
        borrowRecord.setStatus(BorrowStatus.RETURNED);

        // 更新图书可借册数
        Book book = borrowRecord.getBook();
        book.returnBook();
        bookRepository.save(book);

        return borrowRecordRepository.save(borrowRecord);
    }

    @Override
    public BorrowRecord renewBook(Long borrowRecordId, int renewDays) {
        log.info("续借借阅记录: {}", borrowRecordId);

        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        // 检查是否可以续借
        if (!borrowRecord.canRenew(MAX_RENEW_TIMES)) {
            throw new RuntimeException("该借阅记录无法续借");
        }

        // 执行续借
        boolean success = borrowRecord.renew(renewDays, MAX_RENEW_TIMES);
        if (!success) {
            throw new RuntimeException("续借失败");
        }

        return borrowRecordRepository.save(borrowRecord);
    }

    @Override
    public List<BorrowRecord> findByUserId(Long userId) {
        return borrowRecordRepository.findByUserId(userId);
    }

    @Override
    public List<BorrowRecord> findByBookId(Long bookId) {
        return borrowRecordRepository.findByBookId(bookId);
    }

    @Override
    public List<BorrowRecord> findByStatus(BorrowStatus status) {
        return borrowRecordRepository.findByStatus(status);
    }

    @Override
    public List<BorrowRecord> findCurrentBorrowRecords() {
        return borrowRecordRepository.findCurrentBorrowRecords();
    }

    @Override
    public List<BorrowRecord> findOverdueRecords() {
        return borrowRecordRepository.findOverdueRecords();
    }

    @Override
    public List<BorrowRecord> findDueSoonRecords(int days) {
        LocalDateTime startDate = LocalDateTime.now();
        LocalDateTime endDate = LocalDateTime.now().plusDays(days);
        return borrowRecordRepository.findDueSoonRecords(startDate, endDate);
    }

    @Override
    public Page<BorrowRecord> findByUserId(Long userId, Pageable pageable) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在: " + userId));
        return borrowRecordRepository.findByUser(user, pageable);
    }

    @Override
    public boolean isBookBorrowedByUser(Long userId, Long bookId) {
        return borrowRecordRepository.existsByUserIdAndBookIdAndNotReturned(userId, bookId);
    }

    @Override
    public long getCurrentBorrowCountByUser(Long userId) {
        return borrowRecordRepository.countCurrentBorrowsByUserId(userId);
    }

    @Override
    public long countBorrowsByUser(Long userId) {
        return borrowRecordRepository.countByUserId(userId);
    }

    @Override
    public long countBorrowsByBook(Long bookId) {
        return borrowRecordRepository.countByBookId(bookId);
    }

    @Override
    public void calculateAndUpdateOverdue(Long borrowRecordId) {
        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        // 计算逾期天数
        int overdueDays = borrowRecord.calculateOverdueDays();
        if (overdueDays > 0) {
            borrowRecord.setOverdueDays(overdueDays);
            borrowRecord.setStatus(BorrowStatus.OVERDUE);
            borrowRecordRepository.save(borrowRecord);
        }
    }

    @Override
    public void batchCalculateAndUpdateOverdue() {
        List<BorrowRecord> currentBorrows = borrowRecordRepository.findCurrentBorrowRecords();
        for (BorrowRecord record : currentBorrows) {
            if (record.isOverdue()) {
                record.setOverdueDays(record.calculateOverdueDays());
                record.setStatus(BorrowStatus.OVERDUE);
                borrowRecordRepository.save(record);
            }
        }
    }

    @Override
    public boolean canRenew(Long borrowRecordId, int maxRenewTimes) {
        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        return borrowRecord.canRenew(maxRenewTimes);
    }

    @Override
    public BorrowRecord getBorrowRecordDetail(Long borrowRecordId) {
        return borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));
    }

    @Override
    public List<BorrowRecord> findBorrowsInLastDays(int days) {
        LocalDateTime startTime = LocalDateTime.now().minusDays(days);
        return borrowRecordRepository.findBorrowsInLastDays(startTime);
    }

    @Override
    public long countOverdueRecords() {
        return borrowRecordRepository.countOverdueRecords();
    }



     @Override
    public BorrowRecord getById(Long id) {
        return borrowRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + id));
    }

}